<template>
  <div>
    <!-- 面包屑导航 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/ome' }">首页</el-breadcrumb-item>
      <el-breadcrumb-item>权限管理</el-breadcrumb-item>
      <el-breadcrumb-item>角色列表</el-breadcrumb-item>
    </el-breadcrumb>
    <!-- 添加角色对话框 -->
    <el-dialog title="添加角色" :visible.sync="addDialogVisible" width="30%" :close-on-click-modal="false" @close="resetForm">
      <!-- 添加角色的form表单区域 -->
      <el-form :model="addRoles" :rules="addRolesRules" ref="addRolesRef" label-width="80px" status-icon>
        <el-form-item label="角色名" prop="addRolesName">
          <el-input v-model="addRoles.addRolesName"></el-input>
        </el-form-item>
        <el-form-item label="角色描述" prop="addRolesDesc">
          <el-input v-model="addRoles.addRolesDesc"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addRolesMassage">确 定</el-button>
      </span>
    </el-dialog>
    <!-- 角色列表区域 -->
    <el-card>
      <!-- 添加角色按钮 -->
      <el-row>
        <el-col :span="24">
          <el-button type="primary" @click="addDialogVisible=true">添加角色</el-button>
        </el-col>
      </el-row>
      <!-- 角色列表 -->
      <el-table :data="roleList" border stripe>
        <el-table-column type="expand">
          <template slot-scope="scope">
            <el-row v-for="(item1,i1) in scope.row.children" :key="item1.id" :class="['bdbottom',i1===0&&'bdtop','vercenter']">
              <!-- 一级权限区域 -->
              <el-col :span="5">
                <el-tag closable @close="removeRight(scope.row,item1.id)">{{item1.authName}}</el-tag>
                <i class="el-icon-caret-right"></i>
              </el-col>
              <!-- 二、三级权限区域 -->
              <el-col :span="19">
                <el-row v-for="(item2,i2) in item1.children" :key="item2.id" :class="[i2!== 0&&'bdtop','vercenter']">
                  <!-- 二级权限渲染 -->
                  <el-col :span="6">
                    <el-tag type="success" closable @close="removeRight(scope.row,item2.id)">{{item2.authName}}</el-tag>
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <!-- 三级权限渲染 -->
                  <el-col :span="18">
                    <el-tag closable type="warning" v-for="(item3) in item2.children" :key="item3.id" @close="removeRight(scope.row,item3.id)">{{item3.authName}}</el-tag>
                  </el-col>
                </el-row>
              </el-col>
            </el-row>
          </template>
        </el-table-column>
        <el-table-column type="index" label="序号"></el-table-column>
        <el-table-column prop="roleName" label="角色名称"></el-table-column>
        <el-table-column prop="roleDesc" label="角色描述"></el-table-column>
        <el-table-column label="操作" width="300">
          <template slot-scope="scope">
            <el-button type="primary" icon="el-icon-edit" size="mini" @click="getEditRole(scope.row.id)">编辑</el-button>
            <el-button type="danger" icon="el-icon-delete" size="mini" @click="delRoles(scope.row.id)">删除</el-button>
            <el-button type="warning" icon="el-icon-setting" size="mini" @click="showRightDialog(scope.row)">分配权限</el-button>
          </template>
        </el-table-column>
      </el-table>
      <!-- 编辑角色对话框 -->
      <el-dialog title="编辑角色" :visible.sync="editDialogVisible" width="30%" :close-on-click-modal="false" @close="resetEditForm">
        <!-- 编辑角色的form表单区域 -->
        <el-form :model="editRoles" :rules="editRolesRules" ref="editRolesRef" label-width="80px" status-icon>
          <el-form-item label="角色id">
            <el-input v-model="editRoles.roleId" disabled></el-input>
          </el-form-item>
          <el-form-item label="角色名" prop="roleName">
            <el-input v-model="editRoles.roleName"></el-input>
          </el-form-item>
          <el-form-item label="角色描述" prop="roleDesc">
            <el-input v-model="editRoles.roleDesc"></el-input>
          </el-form-item>
        </el-form>
        <span slot="footer" class="dialog-footer">
          <el-button @click="editDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="editRolesMassage">确 定</el-button>
        </span>
      </el-dialog>
      <!-- 分配角色权限对话框 -->
      <el-dialog title="分配权限" :visible.sync="rightDialogVisible" width="50%" :close-on-click-modal="false">
        <!-- 分配权限的树形结构 -->
        <el-tree :data="rightList" show-checkbox :props="treeProps" node-key="id" default-expand-all :default-checked-keys="defkeys" ref="treeRef">
        </el-tree>
        <span slot="footer" class="dialog-footer">
          <el-button @click="rightDialogVisible = false">取 消</el-button>
          <el-button type="primary" @click="allotRights">确 定</el-button>
        </span>
      </el-dialog>
    </el-card>
  </div>
</template>

<script>
// 导入请求根路径
import request from '@/utils/request.js'
export default {
  name: 'Roles',
  data() {
    return {
      // 角色列表数据
      roleList: [],
      // 控制添加角色对话框的数据
      addDialogVisible: false,
      // 添加角色需要携带的数据
      addRoles: {
        addRolesName: '',
        addRolesDesc: ''
      },
      // 添加角色的验证规则数据
      addRolesRules: {
        addRolesName: [
          { required: true, message: '请输入角色名', trigger: 'blur' },
          { min: 3, max: 6, message: '长度在 3 到 6 个字符', trigger: 'blur' }
        ],
        addRolesDesc: [
          { required: true, message: '请输入角色描述', trigger: 'blur' },
          { min: 3, max: 6, message: '长度在 3 到 6 个字符', trigger: 'blur' }
        ]
      },
      // 控制编辑角色对话框的数据
      editDialogVisible: false,
      // 根据角色ID查询到的数据
      editRoles: {},
      // 提交编辑角色的验证规则数据
      editRolesRules: {
        roleName: [
          { required: true, message: '请输入角色名', trigger: 'blur' },
          { min: 3, max: 6, message: '长度在 3 到 6 个字符', trigger: 'blur' }
        ],
        roleDesc: [
          { required: true, message: '请输入角色描述', trigger: 'blur' },
          { min: 3, max: 6, message: '长度在 3 到 6 个字符', trigger: 'blur' }
        ]
      },
      // 控制分配权限对话框的数据
      rightDialogVisible: false,
      // 角色权限的数据
      rightList: [],
      // 角色权限的树形结构属性数据
      treeProps: {
        children: 'children',
        label: 'authName'
      },
      // 树形结构中已有的角色权限数据
      defkeys: [],
      // 分配角色权限使用的当前角色数据
      rolesId: '',
      // 分配角色使用的当前选中对的权限数据字符串集合
      idStr: ''
    }
  },
  created() {
    this.getRolesList()
  },
  methods: {
    // 请求角色数据的方法
    async getRolesList() {
      const { data: res } = await request.get('roles')
      // 请求失败则提示
      if (res.meta.status !== 200) {
        this.$message.error('获取角色数据失败')
      }
      // 请求成功传数据给roleList，进行渲染
      this.roleList = res.data
    },
    // 关闭对话框重置添加form表单
    resetForm() {
      this.$refs.addRolesRef.resetFields()
    },
    // 请求添加角色预认证form信息
    addRolesMassage() {
      this.$refs.addRolesRef.validate(async val => {
        if (!val) {
          return this.$message.error('角色信息不符合，请重新填写')
        }
        const { data: res } = await request.post('roles', { roleName: this.addRoles.addRolesName, roleDesc: this.addRoles.addRolesDesc })
        if (res.meta.status !== 201) {
          return this.$message.error('添加角色信息失败')
        }
        this.getRolesList()
        this.addDialogVisible = false
        this.$message.success('添加角色成功')
      })
    },
    // 关闭对话框重置编辑form表单
    resetEditForm() {
      this.$refs.editRolesRef.resetFields()
    },
    // 请求查询角色数据的方法
    async getEditRole(rolesId) {
      const { data: res } = await request.get(`roles/${rolesId}`)
      if (res.meta.status !== 200) {
        return this.$message.error('获取角色信息失败')
      }
      this.editRoles = res.data
      this.editDialogVisible = true
    },
    // 请求编辑角色预认证form信息
    editRolesMassage() {
      this.$refs.editRolesRef.validate(async val => {
        if (!val) {
          return this.$message.error('角色信息不符合，请重新填写')
        }
        const { data: res } = await request.put(`roles/${this.editRoles.roleId}`, {
          params: { roleName: this.editRoles.roleName, roleDesc: this.editRoles.roleDesc }
        })
        // 请求失败时提示用户
        if (res.meta.status !== 200) {
          return this.$message.error('用户信息修改失败')
        }
        // 成功时关闭对话框，刷新列表、提示成功
        this.editDialogVisible = false
        this.getRolesList()
        this.$message.success('成功修改用户信息')
      })
    },
    // 删除角色的方法
    async delRoles(rolesId) {
      const confirm = await this.$confirm('此操作将永久删除该角色, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(error => error)
      if (confirm !== 'confirm') {
        return false
      }
      // 点击确定删除则发请求删用户信息
      const { data: result } = await request.delete(`roles/${rolesId}`)
      if (result.meta.status !== 200) {
        return this.$message.error('角色信息删除失败')
      }
      this.getRolesList()
      this.$message.success('成功修改用户信息')
    },
    // 删除角色权限
    async removeRight(role, rightId) {
      const confirm = await this.$confirm('此操作将永久删除该角色权限, 是否继续?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).catch(error => error)
      if (confirm !== 'confirm') {
        return false
      }
      // 点击确定删除角色权限则发请求
      const { data: result } = await request.delete(`roles/${role.id}/rights/${rightId}`)
      if (result.meta.status !== 200) {
        return this.$message.error('角色权限删除失败')
      }
      // 更改请求回来的当前角色的最新权限,这样可以做到不刷新角色权限列表
      role.children = result.data
      this.$message.success('成功删除用户权限')
    },
    // 分配角色权限的方法
    async showRightDialog(role) {
      // 存当前角色的角色ID，给allotRights函数分配权限使用
      this.rolesId = role.id
      // 使用递归寻找当前角色权限时先清空defkeys数组，这样避免点击不同的角色时权限都会叠加前一个角色的权限
      this.defkeys = []
      const { data: res } = await request.get('rights/tree')
      if (res.meta.status !== 200) {
        return this.$message.error('获取权限失败')
      }
      this.rightList = res.data
      // 递归函数找到的当前角色的所有权限ID数组
      this.getLeafList(role, this.defkeys)
      this.rightDialogVisible = true
    },
    // 定义递归函数，找出角色权限的ID数组给树形结构的勾选框使用
    getLeafList(node, arr) {
      // 如果循环到三级节点直接返回最新的ID数组
      if (!node.children) {
        return arr.push(node.id)
      }
      // 如果不是三级节点则一直调用本身直到找完所有三级节点
      node.children.forEach(item => {
        this.getLeafList(item, arr)
      })
    },
    // 分配权限的方法
    async allotRights() {
      const keys = [...this.$refs.treeRef.getCheckedKeys(), ...this.$refs.treeRef.getHalfCheckedKeys()]
      this.idStr = keys.join(',')
      const { data: res } = await request.post(`roles/${this.rolesId}/rights`, { rids: this.idStr })
      if (res.meta.status !== 200) {
        return this.$message.error('分配权限失败')
      }
      // 请求成功重新刷新角色列表
      this.getRolesList()
      this.$message.success('成功分配角色权限')
      this.rightDialogVisible = false
    }
  }
}
</script>

<style lang="less" scoped>
.el-tag {
  margin: 7px;
}
.bdtop {
  border-top: 1px solid #eee;
}
.bdbottom {
  border-bottom: 1px solid #eee;
}
.vercenter {
  display: flex;
  align-items: center;
}
</style>